﻿/* =========================================================================================
 * Copyright (C) 2014 Rajdeep Podder
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *  
 * ========================================================================================= */

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;
using ReCaptcha.Mvc5.Model;
using System.Text;
using System.Threading;

namespace ReCaptcha.Mvc5
{
    /// <summary>
    /// Recapcha utility class.
    /// </summary>
    public class reCAPTCHAApi
    {
        /// <summary>
        /// Recaptcha verification api
        /// </summary>
        /// <param name="hostaddress">IPv4 address of request client.</param>
        /// <param name="model">View model of recaptcha challenge.</param>
        /// <param name="secure">whether to use https or not.</param>
        /// <param name="privatekey">Recaptcha private key cref = "https://www.google.com/recaptcha/admin/create "</param>
        /// <returns>ReCaptcha server response</returns>
        public static async Task<ReCaptchaResponse> verify(string hostaddress,
            ReCaptchaViewModel model,
            String privatekey,
            bool secure = false)
        {
            var recaptchaResponse = new ReCaptchaResponse();

            var recaptchaValidationForm = new MultipartFormDataContent();
            recaptchaValidationForm.Add(new StringContent(privatekey), "privatekey");
            recaptchaValidationForm.Add(new StringContent(hostaddress), "remoteip");
            recaptchaValidationForm.Add(new StringContent(model.recaptcha_challenge_field), "challenge");
            recaptchaValidationForm.Add(new StringContent(model.recaptcha_response_field), "response");

            var verifyUrl = Utility.FormatUrl(ReCaptchaConfig.VerifyUrl, secure);

            var httpClient = new HttpClient();
            try
            {
                HttpResponseMessage response = await httpClient.PostAsync(
                    verifyUrl, recaptchaValidationForm).
                    ConfigureAwait(false);

                if ((int)response.StatusCode == 200)
                {
                    var contentString = await response.Content.
                                                ReadAsStringAsync();                    

                    recaptchaResponse.ParseResponse(contentString);
                }
            }
            catch (Exception)
            {

            }

            return recaptchaResponse;
        }

        /// <summary>
        /// Generates Recaptcha html string
        /// cref ="https://developers.google.com/recaptcha/docs/customization"
        /// </summary>
        /// <param name="publickey">Public key for recaptcha cref = "https://www.google.com/recaptcha/admin/create"</param>
        /// <param name="secure">Whether to use https</param>
        /// <param name="theme">Recaptcha theme. Default is red.</param>
        /// <param name="lang">Language code for recptcha ui. Default is "en".</param>
        /// <param name="custom_translations">Map for custom translation string.</param>
        /// <param name="custom_theme_widget">Hrml element id if you are using custom theme.</param>
        /// <param name="tabindex">Tab index of the user response textbox.</param>
        /// <returns>Html string for recaptcha.</returns>
        public static string reCAPTCHAHtmlString(string publickey,
            bool secure,
            string theme = ReCaptchaThemes.red,
            string lang = "en",
            IDictionary<string, string> custom_translations = null,
            string custom_theme_widget = null,
            int tabindex = 0)
        {
            var sb_customize = new StringBuilder();

            var startchar = "";
            sb_customize.Append("<script type=\"text/javascript\">\nvar RecaptchaOptions = {");

            if ((custom_translations != null) && (custom_translations.Count > 0))
            {
                sb_customize.Append("custom_translations : {");
                foreach(var item in custom_translations)
                {
                    sb_customize.Append(String.Format("{0}\n\t{1} : '{2}'",
                        startchar, item.Key, item.Value));
                }
                sb_customize.Append(String.Format("{0}\n}", startchar));
                startchar = ",";
            }

            if (!String.IsNullOrEmpty(theme) &&
                !theme.Equals(ReCaptchaThemes.red, StringComparison.InvariantCultureIgnoreCase))
            {
                sb_customize.Append(String.Format("{0}\ntheme : '{1}'", startchar, theme));
                startchar = ",";
            }

            if (!String.IsNullOrEmpty(lang) &&
                !lang.Equals("en", StringComparison.InvariantCultureIgnoreCase))
            {
                sb_customize.Append(String.Format("{0}\nlang : '{1}'", startchar, lang));
                startchar = ",";
            }

            if (!String.IsNullOrEmpty(custom_theme_widget))
            {
                sb_customize.Append(String.Format("{0}\ncustom_theme_widget : '{1}'",
                    startchar, custom_theme_widget));
                startchar = ",";
            }

            if (tabindex > 0)
            {
                sb_customize.Append(String.Format("{0}\ntabindex : {1}", startchar, tabindex));
                startchar = ",";
            }

            sb_customize.Append(String.Format("{0}\n}};\n</script>\n", startchar));
            StringBuilder sbHtml = new StringBuilder();
            if (startchar.Length > 0)
            {
                sbHtml.Append(sb_customize);
            }

            sbHtml.Append(String.Format("<script type=\"text/javascript\"src=\"{0}{1}\"> </script>", 
                                    Utility.FormatUrl("www.google.com/recaptcha/api/challenge?k=", secure),
                                    publickey));

            sbHtml.Append("<noscript>\n");
            sbHtml.Append(
                String.Format(
                "<iframe src=\"{0}{1}\" height=\"300\" width=\"500\" frameborder=\"0\"></iframe>\n",
                Utility.FormatUrl("www.google.com/recaptcha/api/noscript?k=", secure),
                publickey));
            sbHtml.Append("<br><textarea name=\"recaptcha_challenge_field\" rows=\"3\" cols=\"40\"></textarea>\n");
            sbHtml.Append("<input type=\"hidden\" name=\"recaptcha_response_field\" value=\"manual_challenge\">\n");
            sbHtml.Append("</noscript>");
            return sbHtml.ToString();
        }
    }
}
